/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * PublicHolidayEditor.java
 *
 * Created on 14-Apr-2011, 23:00:45
 */

package TimeRecording.forms;

import TimeRecording.business.HolidayCalculations;
import TimeRecording.enums.HolidayRequestStatus;
import TimeRecording.enums.PartOfDay;
import TimeRecording.tables.Employee;
import TimeRecording.tables.HolidayRequest;
import TimeRecording.tables.PublicHoliday;
import java.awt.Component;
import java.awt.Cursor;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.swing.JCheckBox;
import javax.swing.JOptionPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import org.jdesktop.application.Action;

/**
 *
 * @author david
 */
public class PublicHolidayGrantDialog extends javax.swing.JDialog {

    private final static Logger LOGGER = Logger.getLogger(
            PublicHolidayGrantDialog.class.getName());

    // <editor-fold defaultstate="collapsed" desc="publicHoliday + Getter & Setter">
    private PublicHoliday publicHoliday;

    public PublicHoliday getPublicHoliday() {
        return publicHoliday;
    }

    public void setPublicHoliday(PublicHoliday publicHoliday) {
        PublicHoliday oldPublicHoliday = this.publicHoliday;
        this.publicHoliday = publicHoliday;
        firePropertyChange("publicHoliday", oldPublicHoliday, publicHoliday);
        populateTable(publicHoliday.getDateOfHoliday());
    } // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="saved + Getter & Setter">
    private boolean saved;

    public boolean getSaved() {
        return saved;
    }

    public void setSaved(boolean saved) {
        boolean oldSaved = this.saved;
        this.saved = saved;
        firePropertyChange("saved", oldSaved, saved);
    } // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Custom Rendered">
    private class ToolTipRenderer extends JCheckBox implements TableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {

            boolean checked = (Boolean)value;
            this.setSelected(checked);
            this.setHorizontalAlignment(SwingConstants.CENTER);
            this.setBackground(table.getBackground());
            
            if (!table.getModel().isCellEditable(row, column)) {
                this.setToolTipText(
                        "Cannot be cancelled as " +
                        "part of a longer holiday");
            } else {
                this.setToolTipText(null);
            }

            return this;
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Private holiday-employee DTO">
    private class EmployeePublicHoliday {
        
        private Employee employee;
        private boolean booked;
        private boolean editable;
        private boolean keepBooked;

        public EmployeePublicHoliday(Employee employee,
                boolean booked, boolean editable) {

            this.employee = employee;
            this.booked = booked;
            this.editable = editable;
            this.keepBooked = booked;
        }

        public Employee getEmployee() {
            return employee;
        }

        public boolean isBooked() {
            return keepBooked;
        }

        public void setBooked(boolean keepBooked) {
            this.keepBooked = keepBooked;
        }

        public boolean isEditable() {
            return editable;
        }

        public boolean changed() {
            return booked != keepBooked;
        }
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="Table Model">
    private class EmployeePublicHolidayTable extends DefaultTableModel {

        private final String[] HEADINGS = new String[] {
                "Employee", "Holiday Booked"};

        private List<EmployeePublicHoliday> employeeHolidays;

        public void setEmployeePublicHoliday(
                List<EmployeePublicHoliday> employeePublicHolidays) {
            
            this.employeeHolidays = employeePublicHolidays;
            fireTableDataChanged();
        }

        @Override
        public int getColumnCount() {
            return 2;
        }

        @Override
        public int getRowCount() {
            if (employeeHolidays != null) {
                return employeeHolidays.size();
            } else {
                return 0;
            }
        }

        @Override
        public String getColumnName(int column) {
            return HEADINGS[column];
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return employeeHolidays.get(row).isEditable();
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == 0) {
                return String.class;
            } else {
                return Boolean.class;
            }
        }

        @Override
        public Object getValueAt(int row, int column) {
            if (column == 0) {
                return employeeHolidays.get(row).getEmployee();
            } else if (column == 1) {
                return new Boolean(employeeHolidays.get(row).isBooked());
            } else {
                return null;
            }
        }

        @SuppressWarnings("unchecked")
        @Override
        public void setValueAt(Object aValue, int row, int column) {
            employeeHolidays.get(row).setBooked((Boolean)aValue);
        }

        public void selectAll() {
            for (EmployeePublicHoliday employeeHoliday : employeeHolidays) {
                if (employeeHoliday.isEditable()) {
                    employeeHoliday.setBooked(true);
                }
            }
            fireTableDataChanged();
        }

        public void deselectAll() {
            for (EmployeePublicHoliday employeeHoliday : employeeHolidays) {
                if (employeeHoliday.isEditable()) {
                    employeeHoliday.setBooked(false);
                }
            }
            fireTableDataChanged();
        }
    }
    // </editor-fold>

    private EmployeePublicHolidayTable model = new EmployeePublicHolidayTable();
    private ToolTipRenderer toolTipRenderer = new ToolTipRenderer();
    private List<EmployeePublicHoliday> employeePublicHolidays;
    
    /** Creates new form PublicHolidayEditor */
    public PublicHolidayGrantDialog(PublicHolidayDialog parent) {
        super(parent, true);
        myParent = parent;
        initComponents();
        employeeTable.getColumnModel().getColumn(1).
                setCellRenderer(toolTipRenderer);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;
        bindingGroup = new org.jdesktop.beansbinding.BindingGroup();

        holidayIdLabel = new javax.swing.JLabel();
        holidayId = new javax.swing.JTextField();
        dateOfHolidayLabel = new javax.swing.JLabel();
        buttonPanel = new javax.swing.JPanel();
        okButton = new javax.swing.JButton();
        cancelButton = new javax.swing.JButton();
        selectAllButton = new javax.swing.JButton();
        deselectAllButton = new javax.swing.JButton();
        descriptionLabel = new javax.swing.JLabel();
        description = new javax.swing.JTextField();
        employeePane = new javax.swing.JScrollPane();
        employeeTable = new javax.swing.JTable();
        jFormattedTextField1 = new javax.swing.JFormattedTextField();

        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(TimeRecording.TimeRecordingApp.class).getContext().getResourceMap(PublicHolidayGrantDialog.class);
        setTitle(resourceMap.getString("Form.title")); // NOI18N
        setName("Form"); // NOI18N
        getContentPane().setLayout(new java.awt.GridBagLayout());

        holidayIdLabel.setText(resourceMap.getString("holidayIdLabel.text")); // NOI18N
        holidayIdLabel.setName("holidayIdLabel"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(4, 8, 4, 4);
        getContentPane().add(holidayIdLabel, gridBagConstraints);

        holidayId.setEditable(false);
        holidayId.setMaximumSize(new java.awt.Dimension(100, 2147483647));
        holidayId.setMinimumSize(new java.awt.Dimension(100, 20));
        holidayId.setName("holidayId"); // NOI18N
        holidayId.setPreferredSize(new java.awt.Dimension(100, 20));

        org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${publicHoliday.holidayId}"), holidayId, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 8);
        getContentPane().add(holidayId, gridBagConstraints);

        dateOfHolidayLabel.setText(resourceMap.getString("dateOfHolidayLabel.text")); // NOI18N
        dateOfHolidayLabel.setName("dateOfHolidayLabel"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(4, 8, 4, 4);
        getContentPane().add(dateOfHolidayLabel, gridBagConstraints);

        buttonPanel.setName("buttonPanel"); // NOI18N

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(TimeRecording.TimeRecordingApp.class).getContext().getActionMap(PublicHolidayGrantDialog.class, this);
        okButton.setAction(actionMap.get("okClicked")); // NOI18N
        okButton.setText(resourceMap.getString("okButton.text")); // NOI18N
        okButton.setName("okButton"); // NOI18N
        buttonPanel.add(okButton);

        cancelButton.setAction(actionMap.get("cancelClicked")); // NOI18N
        cancelButton.setText(resourceMap.getString("cancelButton.text")); // NOI18N
        cancelButton.setName("cancelButton"); // NOI18N
        buttonPanel.add(cancelButton);

        selectAllButton.setAction(actionMap.get("selectAllClicked")); // NOI18N
        selectAllButton.setText(resourceMap.getString("selectAllButton.text")); // NOI18N
        selectAllButton.setName("selectAllButton"); // NOI18N
        buttonPanel.add(selectAllButton);

        deselectAllButton.setAction(actionMap.get("deselectAllClicked")); // NOI18N
        deselectAllButton.setText(resourceMap.getString("deselectAllButton.text")); // NOI18N
        deselectAllButton.setName("deselectAllButton"); // NOI18N
        buttonPanel.add(deselectAllButton);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 4;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        getContentPane().add(buttonPanel, gridBagConstraints);

        descriptionLabel.setText(resourceMap.getString("descriptionLabel.text")); // NOI18N
        descriptionLabel.setName("descriptionLabel"); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
        gridBagConstraints.insets = new java.awt.Insets(4, 8, 4, 4);
        getContentPane().add(descriptionLabel, gridBagConstraints);

        description.setEditable(false);
        description.setName("description"); // NOI18N

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${publicHoliday.description}"), description, org.jdesktop.beansbinding.BeanProperty.create("text"));
        bindingGroup.addBinding(binding);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 8);
        getContentPane().add(description, gridBagConstraints);

        employeePane.setName("employeePane"); // NOI18N

        employeeTable.setModel(model);
        employeeTable.setName("employeeTable"); // NOI18N
        employeePane.setViewportView(employeeTable);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.gridwidth = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.weightx = 2.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new java.awt.Insets(4, 8, 4, 8);
        getContentPane().add(employeePane, gridBagConstraints);

        jFormattedTextField1.setEditable(false);
        jFormattedTextField1.setFormatterFactory(new javax.swing.text.DefaultFormatterFactory(new javax.swing.text.DateFormatter(java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT))));
        jFormattedTextField1.setText(resourceMap.getString("jFormattedTextField1.text")); // NOI18N
        jFormattedTextField1.setName("jFormattedTextField1"); // NOI18N

        binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, this, org.jdesktop.beansbinding.ELProperty.create("${publicHoliday.dateOfHoliday}"), jFormattedTextField1, org.jdesktop.beansbinding.BeanProperty.create("value"));
        bindingGroup.addBinding(binding);

        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 1;
        gridBagConstraints.gridy = 2;
        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
        gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 8);
        getContentPane().add(jFormattedTextField1, gridBagConstraints);

        bindingGroup.bind();

        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
        setBounds((screenSize.width-416)/2, (screenSize.height-358)/2, 416, 358);
    }// </editor-fold>//GEN-END:initComponents

    @SuppressWarnings("unchecked")
    private void populateTable(Date date) {
        
        List<Employee> employees =
                Employee.getActiveEmployees(myParent.getEntityManager());

        employeePublicHolidays =
                new ArrayList<EmployeePublicHoliday>(employees.size());

        for (Employee employee : employees) {

            boolean booked = HolidayCalculations.
                    isOnHoliday(employee, date, false) == PartOfDay.ALL_DAY;

            boolean editable = !booked || HolidayCalculations.
                    singleDayBooked(employee, date, false);
            
            employeePublicHolidays.add(new EmployeePublicHoliday(
                    employee, booked, editable));
        }

        model.setEmployeePublicHoliday(employeePublicHolidays);
    }

    public void saveChanges() {

        EntityManager entityManager = myParent.getEntityManager();
        Cursor savedCursor = null;

        try {
            savedCursor = getCursor();
            setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            entityManager.getTransaction().begin();

            for (EmployeePublicHoliday employeeHoliday : employeePublicHolidays) {
                
                if (employeeHoliday.changed()) {
                    
                    if (employeeHoliday.isBooked()) {

                        HolidayRequest holiday = new HolidayRequest();

                        holiday.setEmployeeId(employeeHoliday.employee);
                        holiday.setFirstDayOfHoliday(publicHoliday.getDateOfHoliday());
                        holiday.setFirstDayPart(PartOfDay.ALL_DAY);
                        holiday.setLastDayOfHoliday(publicHoliday.getDateOfHoliday());
                        holiday.setLastDayPart(PartOfDay.ALL_DAY);

                        holiday.setAdministratorComment(publicHoliday.getDescription());
                        holiday.setAdministratorId(null);

                        holiday.setStatus(HolidayRequestStatus.APPROVED);

                        if (!HolidayCalculations.validateRequest(holiday)) {
                            JOptionPane.showMessageDialog(this, "Holiday Clash",
                                    "Gant Public Holiday", JOptionPane.ERROR_MESSAGE);
                            entityManager.getTransaction().rollback();
                            return;
                        }

                        entityManager.persist(holiday);
                        employeeHoliday.employee.getHolidayRequests().add(holiday);

                    } else {

                        HolidayRequest holiday = HolidayCalculations.
                                getPublicHoliday(
                                        employeeHoliday.getEmployee(),
                                        publicHoliday.getDateOfHoliday());

                        if (holiday != null) {
                            entityManager.remove(holiday);
                            employeeHoliday.employee.getHolidayRequests().remove(holiday);
                        }
                    }
                }
            }

            entityManager.getTransaction().commit();

        } catch (RuntimeException e) {
            LOGGER.log(Level.SEVERE, "Error granting/revoking pubnlic holiday", e);
            if (entityManager.getTransaction().isActive()) {
                entityManager.getTransaction().rollback();
            }
            ErrorDialog.showError(this, e);
            
        } finally {
            setCursor(savedCursor);
        }
    }

    @Action
    public void okClicked() {
        saveChanges();
        setSaved(true);
        setVisible(false);
    }

    @Action
    public void cancelClicked() {
        setSaved(false);
        setVisible(false);
    }

    @Action
    public void selectAllClicked() {
        model.selectAll();
    }

    @Action
    public void deselectAllClicked() {
        model.deselectAll();
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel buttonPanel;
    private javax.swing.JButton cancelButton;
    private javax.swing.JLabel dateOfHolidayLabel;
    private javax.swing.JTextField description;
    private javax.swing.JLabel descriptionLabel;
    private javax.swing.JButton deselectAllButton;
    private javax.swing.JScrollPane employeePane;
    private javax.swing.JTable employeeTable;
    private javax.swing.JTextField holidayId;
    private javax.swing.JLabel holidayIdLabel;
    private javax.swing.JFormattedTextField jFormattedTextField1;
    private javax.swing.JButton okButton;
    private javax.swing.JButton selectAllButton;
    private org.jdesktop.beansbinding.BindingGroup bindingGroup;
    // End of variables declaration//GEN-END:variables

    private PublicHolidayDialog myParent;
}
